package cn.signalpha.modules.pay.granter;

import cn.signalpha.common.cache.ConfigCache;
import cn.signalpha.common.cache.ConfigKeys;
import cn.signalpha.common.dto.ConfigDTO;
import cn.signalpha.core.log.exception.ServiceException;
import cn.signalpha.core.tool.utils.StringPool;
import cn.signalpha.modules.pay.dto.PayDTO;
import cn.signalpha.modules.pay.dto.RefundDTO;
import cn.signalpha.modules.pay.dto.SettleOrderDTO;
import cn.signalpha.modules.pay.dto.SettleUserDTO;
import cn.signalpha.modules.pay.enums.PayClientEnum;
import cn.signalpha.modules.pay.provider.IPayGranter;
import cn.signalpha.modules.pay.vo.RefundVO;
import cn.signalpha.modules.pay.vo.SettleOrderVO;
import cn.signalpha.modules.pay.vo.SettleUserVO;
import com.alibaba.fastjson.JSONObject;
import com.alipay.api.AlipayApiException;
import com.alipay.api.domain.AlipayTradeAppPayModel;
import com.alipay.api.domain.AlipayTradePrecreateModel;
import com.alipay.api.domain.AlipayTradeRefundModel;
import com.alipay.api.domain.AlipayTradeWapPayModel;
import com.alipay.api.internal.util.AlipaySignature;
import com.ijpay.alipay.AliPayApi;
import com.ijpay.alipay.AliPayApiConfig;
import com.ijpay.alipay.AliPayApiConfigKit;
import lombok.AllArgsConstructor;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import java.util.Map;
import java.util.Objects;

/**
 * 阿里支付
 *
 * @author signalpha
 */
@Slf4j
@Component
@AllArgsConstructor
public class AliPayGranter implements IPayGranter {

	@Override
	public String getPayVO(PayDTO payDTO) {
		ConfigDTO.AliPayDTO config = ConfigCache.getObject(ConfigKeys.ALI_PAY, ConfigDTO.AliPayDTO.class);
		payDTO.setNotifyUrl(config.getDomain().concat(payDTO.getNotifyUrl()).concat("/ali"));
		switch (Objects.requireNonNull(PayClientEnum.instance(payDTO.getPayClient()), "支付终端错误")){
			case H5:
				return aliH5Pay(payDTO);
			case APP:
				return aliAppPay(payDTO);
			case NATIVE2:
				return aliNative2Pay(payDTO);
			default:
				throw new ServiceException("终端未实现");
		}
	}

	@Override
	public String verifyNotify(Map<String, String> params) {
		boolean verifyResult;
		AliPayApiConfig aliPayApiConfig = AliPayApiConfigKit.getAliPayApiConfig();
		try {
			verifyResult = AlipaySignature.rsaCheckV1(params, aliPayApiConfig.getAliPayPublicKey(), "UTF-8", "RSA2");
		} catch (AlipayApiException e) {
			log.error("支付宝回调验证签名异常：", e);
			return StringPool.FALSE;
		}
		if(!verifyResult){
			log.info("支付宝回调验证签名失败");
			return StringPool.FALSE;
		}
		//若参数中的appid和填入的appid不相同，则为异常通知
		if (!aliPayApiConfig.getAppId().equals(params.get("app_id"))) {
			log.info("支付宝回调验证签名成功，与付款时的appid不同，此为异常通知，应忽略！");
			return StringPool.FALSE;
		}
		String outTradeNo = params.get("out_trade_no");
		String status = params.get("trade_status");
		if("WAIT_BUYER_PAY".equals(status)){
			log.info(outTradeNo + "订单的状态正在等待用户付款");
			return StringPool.FALSE;
		}
		if ("TRADE_CLOSED".equals(status)){
			log.info(outTradeNo + "订单的状态已经关闭");
			return StringPool.FALSE;
		}
		if ("TRADE_SUCCESS".equals(status) || "TRADE_FINISHED".equals(status)){
			log.info("(支付宝订单号:"+outTradeNo+"付款成功)");
			return StringPool.TRUE;
		}
		return StringPool.FALSE;
	}

	@Override
	@SneakyThrows
	public RefundVO refund(RefundDTO refundDTO) {
		AlipayTradeRefundModel model = new AlipayTradeRefundModel();
		model.setOutTradeNo(refundDTO.getPayNo());
		model.setTradeNo(refundDTO.getPayBizNo());
		model.setOutRequestNo(refundDTO.getRefundNo());
		model.setRefundAmount(String.valueOf(refundDTO.getRefundMoney()));
		model.setRefundReason("退款");
		String resultStr = AliPayApi.tradeRefundToResponse(model).getBody();
		JSONObject resultJson = JSONObject.parseObject(resultStr);
		JSONObject responseJson = resultJson.getJSONObject("alipay_trade_refund_response");
		if(!"10000".equals(responseJson.getString("code"))){
			return RefundVO.builder().code(StringPool.NO).msg(responseJson.getString("sub_msg")).build();
		}
		return RefundVO.builder().code(StringPool.YES).orderBizNo(responseJson.getString("trade_no")).build();
	}

	@Override
	public SettleUserVO settleUser(SettleUserDTO settleUserDTO) {
		return SettleUserVO.builder().code(StringPool.NO).msg("该支付未实现分账").build();
	}

	@Override
	public SettleOrderVO settleOrder(SettleOrderDTO settleOrderDTO) {
		return SettleOrderVO.builder().code(StringPool.NO).msg("该支付未实现分账").build();
	}

	/**
	 * 支付宝H5 支付
	 */
	private String aliH5Pay(PayDTO payDTO) {
		AlipayTradeWapPayModel model = new AlipayTradeWapPayModel();
		model.setOutTradeNo(payDTO.getPayNo());
		model.setBody(payDTO.getBody());
		model.setSubject(payDTO.getBody());
		model.setTotalAmount(payDTO.getPayMoney());
		model.setPassbackParams(payDTO.getNotifyParams());

		String data;
		try {
			data = AliPayApi.wapPayStr(model, payDTO.getReturnUrl(), payDTO.getNotifyUrl());
		} catch (AlipayApiException e) {
			throw new ServiceException(e.getErrMsg());
		}
		return data;
	}

	/**
	 * 支付宝APP 支付
	 */
	private String aliAppPay(PayDTO payDTO) {
		AlipayTradeAppPayModel model = new AlipayTradeAppPayModel();
		model.setOutTradeNo(payDTO.getPayNo());
		model.setBody(payDTO.getBody());
		model.setSubject(payDTO.getBody());
		model.setTotalAmount(payDTO.getPayMoney());
		model.setPassbackParams(payDTO.getNotifyParams());

		String data;
		try {
			data = AliPayApi.appPayToResponse(model, payDTO.getNotifyUrl()).getBody();
		} catch (AlipayApiException e) {
			throw new ServiceException(e.getErrMsg());
		}
		return data;
	}

	/**
	 * 支付宝当面付 扫码支付
	 */
	private String aliNative2Pay(PayDTO payDTO) {
		AlipayTradePrecreateModel model = new AlipayTradePrecreateModel();
		model.setOutTradeNo(payDTO.getPayNo());
		model.setBody(payDTO.getBody());
		model.setSubject(payDTO.getBody());
		model.setTotalAmount(payDTO.getPayMoney());
		model.setPassbackParams(payDTO.getNotifyParams());

		String data;
		try {
			String resultStr = AliPayApi.tradePrecreatePayToResponse(model, payDTO.getNotifyUrl()).getBody();
			JSONObject resultJson = JSONObject.parseObject(resultStr);
			JSONObject responseJson = resultJson.getJSONObject("alipay_trade_precreate_response");
			if(!"10000".equals(responseJson.getString("code"))){
				throw new ServiceException(responseJson.getString("sub_msg"));
			}
			data = responseJson.getString("qr_code");
		} catch (AlipayApiException e) {
			throw new ServiceException(e.getErrMsg());
		}
		return data;
	}

}
